package org.atlantis.nio;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

public class NioServer {

	private static final int[] PORTS = new int[] { 5656, 6868 };
	private static final int SELECT_TIMEOUT = 3000;
	private static final int BUFFER_SIZE = 1024;
	private static Selector selector;

	public static void main(String[] args) throws Exception {
		selector = Selector.open();
		for (int port : PORTS) {
			ServerSocketChannel server = ServerSocketChannel.open();
			server.configureBlocking(false);
			server.socket().bind(new InetSocketAddress(port));
			server.register(selector, SelectionKey.OP_ACCEPT);
		}
		while (selector.isOpen()) {
			int selecteds = selector.select(SELECT_TIMEOUT);
			if (selecteds <= 0) continue;
			Iterator<SelectionKey> keys = selector.selectedKeys().iterator();
			while (keys.hasNext()) {
				SelectionKey key = keys.next();
				keys.remove();
				if (key.isAcceptable()) handleAccept(key);
				if (key.isReadable()) handleRead(key);
				if (key.isValid() && key.isWritable()) handleWrite(key);
			}
		}
	}

	private static void handleAccept(SelectionKey key) throws Exception {
		ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE);

		ServerSocketChannel server = (ServerSocketChannel) key.channel();
		SocketChannel client = server.accept();
		client.configureBlocking(false);
		client.register(selector, SelectionKey.OP_READ, buffer);
		System.out.println(String.format("A client '%s' connected.", client.socket().getRemoteSocketAddress()));
	}

	private static void handleRead(SelectionKey key) throws Exception {
		key.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE);
		ByteBuffer buffer = (ByteBuffer) key.attachment();
		SocketChannel client = (SocketChannel) key.channel();
		long size = client.read(buffer);
		if (size == -1) {
			System.out.println(String.format("A client '%s' connected.", client.socket().getRemoteSocketAddress()));
			client.close();
		}
	}

	private static void handleWrite(SelectionKey key) throws Exception {
		ByteBuffer buffer = (ByteBuffer) key.attachment();
		buffer.flip();
		SocketChannel client = (SocketChannel) key.channel();
		client.write(buffer);
		buffer.compact();
	}
}
